home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 11
/
CU Amiga Magazine's Super CD-ROM 11 (1997)(EMAP Images)(GB)(Track 1 of 3)[!][issue 1997-06].iso
/
www
/
http
/
www.amigasupport.com
/
software
/
arc
/
bmpdt.lha
/
BMPdt
/
Source
/
getbmp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-21
|
15KB
|
638 lines
/*
** our include
*/
#include "getbmp.h"
/*
** functions for asynchronous file I/O
*/
APTR OpenFFR(BPTR,LONG);
LONG FFRGetC(APTR);
LONG FFRRead(APTR,APTR,LONG);
VOID CloseFFR(APTR);
/*
** cybergfx defines for picture.datatype V43
*/
#define RECTFMT_RGB 0
#define RECTFMT_LUT8 3
/*
** easy access of a char-array as a "structure" (IJG sources v5.0b)
*/
#define UCH(x) \
((int) (x))
#define GET_2B(array,offset) \
((unsigned int) UCH(array[offset]) + \
(((unsigned int) UCH(array[offset+1])) << 8))
#define GET_4B(array,offset) \
((ULONG) UCH(array[offset]) + \
(((ULONG) UCH(array[offset+1])) << 8) + \
(((ULONG) UCH(array[offset+2])) << 16) + \
(((ULONG) UCH(array[offset+3])) << 24))
/*
** compression types for BMPs
*/
enum { BI_RGB=0,BI_RLE8=1,BI_RLE4=2 };
/*
** get dt attribute(s)
*/
ULONG set_dt_attrs(Object *obj, ULONG data, ...)
{
return (SetDTAttrsA(obj,NULL,NULL,(struct TagItem *)&data));
}
/*
** get dt attribute(s)
*/
ULONG get_dt_attrs(Object *obj, ULONG data, ...)
{
return (GetDTAttrsA(obj,(struct TagItem *)&data));
}
/*
** expand every bit to a byte
*/
VOID convert_1bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
{
ULONG i,j;
UBYTE c;
for(i=width/8; i!=0; i--)
for(c=*pixelbuf++,j=8; j!=0; j--) {
*outbuf++ = ((c & 0x80) ? 1 : 0); c <<= 1;
}
if ((i=width%8)) {
c = *pixelbuf;
do {
*outbuf++ = ((c & 0x80) ? 1 : 0); c <<= 1;
} while (--i);
}
}
/*
** expand every 4 bits to a byte
*/
VOID convert_4bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
{
ULONG i;
UBYTE c;
for(i=width/2; i!=0; i--) {
c = *pixelbuf++; *outbuf++ = (c >> 4); *outbuf++ = (c & 0xf);
}
if (width&1) {
c = *pixelbuf; c >>= 4; *outbuf = c;
}
}
/*
** perform a simple copy (outbuf is WritePixelLine8() aware..)
*/
VOID convert_8bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
{
CopyMem(pixelbuf,outbuf,width);
}
/*
** correct color order (BGR -> RGB)
*/
VOID convert_24bit(UBYTE *pixelbuf, UBYTE *outbuf, ULONG width)
{
UBYTE *p,c;
p = pixelbuf;
do {
c = p[0]; p[0] = p[2]; p[2] = c; p += 3;
} while (p < &pixelbuf[width*3]);
}
/*
** handle 4bit compression
*/
LONG decompress_4bit(APTR handle, UBYTE *buffer, ULONG width, ULONG height)
{
LONG xpos,a,b,c,i;
UBYTE *end;
end = buffer+width*height; xpos = 0;
do {
if ((c=FFRGetC(handle)) < 0) return c;
if (c == 0) {
if ((c=FFRGetC(handle)) < 0) return c;
if (c == 0) {
buffer += (width-xpos); height--; xpos = 0;
}
else if (!--c) {
break;
}
else if (!--c) {
a = FFRGetC(handle); xpos += a; buffer += a;
if ((c=FFRGetC(handle)) < 0) return c;
height -= c; buffer += width*c;
}
else {
c += 2; i = 0;
do {
a = FFRGetC(handle); b = a & 0x0f; a >>= 4;
*buffer++ = a; *buffer++ = b;
i += 2;
} while (i < c);
if (((c&3)==1) || ((c&3)==2)) FFRGetC(handle);
xpos += c; if (i>c) --buffer;
}
}
else {
i = 0; b = FFRGetC(handle); a = b & 0xf; b >>= 4;
do {
*buffer++ = b; *buffer++ = a; i += 2;
} while (i < c);
xpos += c; if (i>c) --buffer;
}
} while (height && buffer < end);
return 0;
}
/*
** handle 8bit compression
*/
LONG decompress_8bit(APTR handle, UBYTE *buffer, ULONG width, ULONG height)
{
LONG xpos,a,c,i;
UBYTE *end;
end = buffer+width*height; xpos = 0;
do {
if ((c=FFRGetC(handle)) < 0) return c;
if (c == 0) {
if ((c=FFRGetC(handle)) < 0) return c;
if (c == 0) {
buffer += (width-xpos); height--; xpos = 0;
}
else if (!--c) {
break;
}
else if (!--c) {
a = FFRGetC(handle); xpos += a; buffer += a;
if ((c=FFRGetC(handle)) < 0) return c;
height -= c; buffer += width*c;
}
else {
c += 2; i = c;
do {
*buffer++ = FFRGetC(handle);
} while (--i);
if (c&1) FFRGetC(handle);
xpos += c;
}
}
else {
i = c; a = FFRGetC(handle);
do {
*buffer++ = a;
} while (--i);
xpos += c;
}
} while (height && buffer < end);
return 0;
}
/*
** compressed image (4 or 8 bit)
*/
LONG decode_rle_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
{
LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
UBYTE *buffer;
LONG ret=ERROR_NO_FREE_STORE;
if ((buffer=AllocPooled(pool,width*height+260)) != NULL)
{
decode = decompress_4bit; if (depth != 4) decode = decompress_8bit;
if ((ret=(*decode)(handle,buffer,width,height)) == 0)
do {
convert_8bit(buffer,lbuf,width);
WritePixelLine8(rp,0,height-1,width,lbuf,trp);
buffer+=width;
} while (--height);
}
return ret;
}
/*
** uncompressed image (1, 4 or 8 bit)
*/
LONG decode_normal_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
{
VOID (*convert)(UBYTE *,UBYTE *,ULONG);
ULONG padwidth;
UBYTE *buffer;
LONG ret=ERROR_NO_FREE_STORE;
padwidth = ((((width * depth) + 31) & ~31) / 8);
if ((buffer=AllocPooled(pool,padwidth)) != NULL)
{
convert = convert_8bit;
if (depth != 8) {
convert = convert_4bit;
if (depth != 4)
convert = convert_1bit;
}
ret = -1;
do {
if (FFRRead(handle,buffer,padwidth) != padwidth)
return ret;
(*convert)(buffer,lbuf,width);
WritePixelLine8(rp,0,height-1,width,lbuf,trp);
} while (--height);
ret = 0;
}
return ret;
}
/*
** convert 24 bit to HAM6/8 (not yet)
*/
LONG decode_truecolor_v42(APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth,
UBYTE *lbuf, struct RastPort *rp, struct RastPort *trp)
{
return ERROR_NOT_IMPLEMENTED;
}
/*
** create the bitmap (V42 interface)
*/
LONG decode_picture_v42(Class *cl, Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd, ULONG title)
{
LONG (*decode)(APTR,APTR,ULONG,ULONG,ULONG,UBYTE *,struct RastPort *,struct RastPort *);
ULONG modeid,width,height,depth;
struct BitMap *tbm,*bm;
struct RastPort trp,rp;
UBYTE *lbuf;
LONG ret=ERROR_NO_FREE_STORE;
width = bmhd->bmh_Width; height = bmhd->bmh_Height; depth = bmhd->bmh_Depth;
if (depth == 24) depth /= 3;
if ((bm=AllocBitMap(width,height,depth,BMF_CLEAR|BMF_DISPLAYABLE,NULL)) != NULL)
{
InitRastPort(&rp); rp.BitMap = bm;
if ((tbm=AllocBitMap(width,1,depth,BMF_CLEAR,NULL)) != NULL)
{
InitRastPort(&trp); trp.BitMap = tbm;
if ((lbuf=AllocPooled(pool,((width+15)&~15))) != NULL)
{
decode = decode_truecolor_v42;
if (bmhd->bmh_Depth != 24) {
decode = decode_normal_v42;
if (bmhd->bmh_Compression) {
bmhd->bmh_Compression = 0; decode = decode_rle_v42;
}
}
if ((ret=(*decode)(pool,handle,width,height,depth,lbuf,&rp,&trp)) == 0)
{
modeid = LORES_KEY;
if ((UWORD)width >= 640)
modeid = HIRES;
if ((UWORD)height >= 400)
modeid |= LACE;
set_dt_attrs(obj,
DTA_ObjName, title,
DTA_NominalHoriz, width,
DTA_NominalVert, height,
PDTA_BitMap, bm,
PDTA_ModeID, modeid,
TAG_DONE);
}
}
FreeBitMap(tbm);
}
if (ret)
FreeBitMap(bm);
}
return ret;
}
/*
** compressed image (4 or 8 bit)
*/
LONG decode_rle_v43(Class *cl, Object *obj, APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth)
{
LONG (*decode)(APTR,UBYTE *,ULONG,ULONG);
UBYTE *buffer;
LONG ret=ERROR_NO_FREE_STORE;
if ((buffer=AllocPooled(pool,width*height+260)) != NULL)
{
decode = decompress_4bit; if (depth != 4) decode = decompress_8bit;
if ((ret=(*decode)(handle,buffer,width,height)) == 0)
do {
DoSuperMethod(cl,obj,
DTM_WRITEPIXELARRAY,buffer,RECTFMT_LUT8,width,0,height-1,width,1);
buffer+=width;
} while (--height);
}
return ret;
}
/*
** uncompressed image (1, 4, 8 or 24 bit)
*/
LONG decode_normal_v43(Class *cl, Object *obj, APTR pool, APTR handle, ULONG width, ULONG height, ULONG depth)
{
VOID (*convert)(UBYTE *,UBYTE *,ULONG);
ULONG padwidth,rectfmt;
UBYTE *buffer,*lbuf;
LONG ret=ERROR_NO_FREE_STORE;
padwidth = ((((width * depth) + 31) & ~31) / 8);
if ((buffer=AllocPooled(pool,padwidth)) != NULL)
{
lbuf = buffer; rectfmt = RECTFMT_RGB; convert = convert_24bit;
if (depth != 24) {
convert = convert_8bit;
if (depth != 8) {
convert = convert_4bit;
if (depth != 4) {
convert = convert_1bit;
}
}
rectfmt = RECTFMT_LUT8; lbuf = AllocPooled(pool,width);
}
if (lbuf != NULL)
{
ret = -1;
do {
if (FFRRead(handle,buffer,padwidth) != padwidth)
return ret;
(*convert)(buffer,lbuf,width);
DoSuperMethod(cl,obj,
DTM_WRITEPIXELARRAY,lbuf,rectfmt,0,0,height-1,width,1);
} while (--height);
ret = 0;
}
}
return ret;
}
/*
** decode picture (V43 interface)
*/
LONG decode_picture_v43(Class *cl, Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd, ULONG title)
{
LONG (*decode)(Class *,Object *,APTR,APTR,ULONG,ULONG,ULONG);
ULONG width,height,depth;
LONG level,number,ret;
level = 0; number = 0;
set_dt_attrs(obj,
PDTA_SourceMode, MODE_V43,
PDTA_ModeID, 0,
DTA_ObjName, title,
DTA_NominalHoriz, width=bmhd->bmh_Width,
DTA_NominalVert, height=bmhd->bmh_Height,
DTA_ErrorLevel, &level,
DTA_ErrorNumber, &number,
TAG_DONE);
ret = number;
if (!level) {
decode = decode_normal_v43;
if (bmhd->bmh_Compression)
{bmhd->bmh_Compression = 0; decode = decode_rle_v43; }
ret = (*decode)(cl,obj,pool,handle,width,height,bmhd->bmh_Depth);
}
return ret;
}
/*
** extract all required information from the bmp header
*/
LONG read_bmp_header(Object *obj, APTR pool, APTR handle, struct BitMapHeader *bmhd)
{
UBYTE header[64],*p[2],*coltab,*cmap,r,g,b;
LONG headerSize;
LONG bfOffBits;
LONG biDepth;
LONG biPlanes;
LONG biCompression;
LONG biClrUsed;
LONG cmapentrysize;
LONG coltabsize;
LONG *cregs;
if (FFRRead(handle,header,18) != 18)
return FALSE;
if (((UWORD)GET_2B(header,0)) != 0x4D42)
return FALSE;
bfOffBits = GET_4B(header,10);
headerSize = GET_4B(header,14);
if (headerSize != 12 && headerSize != 40 && headerSize != 64)
return FALSE;
if (FFRRead(handle,header+4,headerSize-4) != (headerSize-4))
return FALSE;
if (headerSize == 12) { /* OS/2 1.x */
bmhd->bmh_Width = GET_2B(header, 4);
bmhd->bmh_Height = GET_2B(header, 6);
biPlanes = GET_2B(header, 8);
biDepth = GET_2B(header,10);
biCompression = 0;
biClrUsed = 0;
cmapentrysize = 3;
}
else { /* Windows 3.x or OS/2 2.x */
bmhd->bmh_Width = GET_4B(header, 4);
bmhd->bmh_Height = GET_4B(header, 8);
biPlanes = GET_2B(header,12);
biDepth = GET_2B(header,14);
biCompression = GET_4B(header,16);
biClrUsed = GET_4B(header,32);
cmapentrysize = 4;
}
if (biPlanes != 1)
return FALSE;
if (biDepth != 1 && biDepth != 4 && biDepth != 8) {
if (biDepth == 24)
cmapentrysize = 0;
else
return FALSE;
}
if ((bmhd->bmh_PageWidth=bmhd->bmh_Width) == 0 ||
(bmhd->bmh_PageHeight=bmhd->bmh_Height) == 0)
return FALSE;
bmhd->bmh_Depth = biDepth;
bmhd->bmh_Compression = biCompression;
if (bmhd->bmh_Compression && ((biDepth == 4 && biCompression != BI_RLE4) ||
(biDepth == 8 && biCompression != BI_RLE8)))
return FALSE;
if ((coltabsize=cmapentrysize) != 0)
{
if (biClrUsed <= 0)
biClrUsed = 1L << biDepth;
if (biClrUsed > 256)
return FALSE;
(void)set_dt_attrs(obj, PDTA_NumColors,(ULONG)biClrUsed, TAG_DONE);
if ((get_dt_attrs(obj, PDTA_ColorRegisters,(ULONG)&p[0],PDTA_CRegs,(ULONG)&p[1], TAG_DONE)) != 2)
return FALSE;
coltabsize = biClrUsed * cmapentrysize;
if ((coltab=AllocPooled(pool,coltabsize)) == NULL)
return FALSE;
if (FFRRead(handle,coltab,coltabsize) != coltabsize)
return FALSE;
/*
** do not use "struct ColorRegister" for cmap since with the amiga port
** of gcc a sizeof() for this structure is four and not three.. oh well
*/
cmap = (UBYTE *)p[0]; cregs = (LONG *)p[1];
do {
r = coltab[2]; *cmap++ = r; *cregs++ = r << 24;
g = coltab[1]; *cmap++ = g; *cregs++ = g << 24;
b = coltab[0]; *cmap++ = b; *cregs++ = b << 24;
coltab += cmapentrysize;
} while (--biClrUsed);
}
if ((biClrUsed = bfOffBits - (14 + headerSize + coltabsize)) > 0)
do
if (FFRGetC(handle) < 0) break;
while (--biClrUsed);
return (biClrUsed == 0 ? TRUE : FALSE);
}
/*
** load the picture
*/
LONG GetBMP(Class *cl, Object *obj, struct TagItem *attrs)
{
LONG (*decode)(Class *,Object *,APTR,APTR,struct BitMapHeader *,ULONG);
struct BitMapHeader *bmhd;
ULONG *methods,*mptr,id;
LONG error,success;
APTR pool,handle;
BPTR fh;
success = FALSE; error = ERROR_NO_FREE_STORE;
if ((pool=CreatePool(MEMF_CLEAR,1024,1024)) != NULL)
{
if ((get_dt_attrs(obj, DTA_Handle,&fh,PDTA_BitMapHeader,&bmhd, TAG_DONE) == 2) && fh)
{
if ((handle=OpenFFR(fh,0)) != NULL)
{
error = ERROR_OBJECT_WRONG_TYPE;
if (read_bmp_header(obj,pool,handle,bmhd) != FALSE)
{
decode = decode_picture_v42;
if ((get_dt_attrs(obj, DTA_Methods,&methods, TAG_DONE) == 1) && methods)
{
mptr=methods;
do
id=*mptr++;
while ((id != ~0) && (id-=DTM_WRITEPIXELARRAY));
if (!id) decode = decode_picture_v43;
}
if ((error=(*decode)(cl,obj,pool,handle,bmhd,GetTagData(DTA_Name,NULL,attrs))) == 0)
success = TRUE;
}
CloseFFR(handle);
}
}
DeletePool(pool);
}
if (!success && error > 0) SetIoErr(error);
return success;
}